home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / X11R4 / cmds / X / os / sprite / xdmcp.c < prev   
Encoding:
C/C++ Source or Header  |  1990-02-15  |  27.7 KB  |  1,127 lines

  1. /*
  2.  * Copyright 1989 Network Computing Devices, Inc., Mountain View, California.
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and its
  5.  * documentation for any purpose and without fee is hereby granted, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of N.C.D. not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  N.C.D. makes no representations about the
  11.  * suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  */
  15.  
  16. #include "Xos.h"
  17. #include <sys/param.h>
  18. #include <sys/socket.h>
  19. #include <netinet/in.h>
  20. #include <netdb.h>
  21. #include <stdio.h>
  22. #include "X.h"
  23. #include "Xmd.h"
  24. #include "misc.h"
  25. #include "osdep.h"
  26. #include "input.h"
  27. #include "opaque.h"
  28.  
  29. #ifdef XDMCP
  30. #include "Xdmcp.h"
  31.  
  32. extern int argcGlobal;
  33. extern char **argvGlobal;
  34. extern char *display;
  35. extern long EnabledDevices[];
  36. extern long AllClients[];
  37. extern char *defaultDisplayClass;
  38.  
  39. static int            xdmcpSocket, sessionSocket;
  40. static xdmcp_states        state;
  41. static struct sockaddr_in   req_sockaddr;
  42. static int            req_socklen;
  43. static CARD32            SessionID;
  44. static long            timeOutTime;
  45. static int            timeOutRtx;
  46. static long            defaultKeepaliveDormancy = XDM_DEF_DORMANCY;
  47. static long            keepaliveDormancy = XDM_DEF_DORMANCY;
  48. static CARD16            DisplayNumber;
  49. static xdmcp_states        XDM_INIT_STATE = XDM_OFF;
  50. #ifdef HASDES
  51. static char            *xdmAuthCookie;
  52. #endif
  53.  
  54. static XdmcpBuffer        buffer;
  55.  
  56. static struct sockaddr_in   ManagerAddress;
  57.  
  58. static get_manager_by_name(), get_xdmcp_sock();
  59.  
  60. static    receive_packet(), send_packet();
  61. static    timeout(), restart();
  62.  
  63. static    recv_willing_msg();
  64. static    recv_accept_msg(),    recv_decline_msg();
  65. static    recv_refuse_msg(),    recv_failed_msg();
  66. static    recv_alive_msg();
  67.  
  68. static    send_query_msg();
  69. static    send_request_msg();
  70. static    send_manage_msg();
  71. static    send_keepalive_msg();
  72.  
  73. static XdmcpFatal(), XdmcpWarning();
  74. static void XdmcpBlockHandler(), XdmcpWakeupHandler();
  75.  
  76. static short    xdm_udp_port = XDM_UDP_PORT;
  77. static Bool    OneSession = FALSE;
  78.  
  79. XdmcpUseMsg ()
  80. {
  81.     ErrorF("-query host-name       contact named host for XDMCP\n");
  82.     ErrorF("-broadcast             broadcast for XDMCP\n");
  83.     ErrorF("-indirect host-name    contact named host for indirect XDMCP\n");
  84.     ErrorF("-port port-num         UDP port number to send messages to\n");
  85.     ErrorF("-once                  Terminate server after one session\n");
  86.     ErrorF("-class display-class   specify display class to send in manage\n");
  87. #ifdef HASDES
  88.     ErrorF("-cookie xdm-auth-bits  specify the magic cookie for XDMCP\n");
  89. #endif
  90.     ErrorF("-displayID display-id  manufacturer display ID for request\n");
  91. }
  92.  
  93. int 
  94. XdmcpOptions(argc, argv, i)
  95.     int        argc, i;
  96.     char    **argv;
  97. {
  98.     if (strcmp(argv[i], "-query") == 0) {
  99.     get_manager_by_name(argc, argv, ++i);
  100.     XDM_INIT_STATE = XDM_QUERY;
  101.     AccessUsingXdmcp ();
  102.     return (i + 1);
  103.     }
  104.     if (strcmp(argv[i], "-broadcast") == 0) {
  105.     XDM_INIT_STATE = XDM_BROADCAST;
  106.     AccessUsingXdmcp ();
  107.     return (i + 1);
  108.     }
  109.     if (strcmp(argv[i], "-indirect") == 0) {
  110.     get_manager_by_name(argc, argv, ++i);
  111.     XDM_INIT_STATE = XDM_INDIRECT;
  112.     AccessUsingXdmcp ();
  113.     return (i + 1);
  114.     }
  115.     if (strcmp(argv[i], "-port") == 0) {
  116.     ++i;
  117.     xdm_udp_port = atoi(argv[i]);
  118.     return (i + 1);
  119.     }
  120.     if (strcmp(argv[i], "-once") == 0) {
  121.     OneSession = TRUE;
  122.     return (i + 1);
  123.     }
  124.     if (strcmp(argv[i], "-class") == 0) {
  125.     ++i;
  126.     defaultDisplayClass = argv[i];
  127.     return (i + 1);
  128.     }
  129. #ifdef HASDES
  130.     if (strcmp(argv[i], "-cookie") == 0) {
  131.     ++i;
  132.     xdmAuthCookie = argv[i];
  133.     return (i + 1);
  134.     }
  135. #endif
  136.     if (strcmp(argv[i], "-displayID") == 0) {
  137.     ++i;
  138.     XdmcpRegisterManufacturerDisplayID (argv[i], strlen (argv[i]));
  139.     return (i + 1);
  140.     }
  141.     return (i);
  142. }
  143.  
  144. /*
  145.  * This section is a collection of routines for
  146.  * registering server-specific data with the XDMCP
  147.  * state machine.
  148.  */
  149.  
  150.  
  151. /*
  152.  * Save all broadcast addresses away so BroadcastQuery
  153.  * packets get sent everywhere
  154.  */
  155.  
  156. #define MAX_BROADCAST    10
  157.  
  158. static struct sockaddr_in   BroadcastAddresses[MAX_BROADCAST];
  159. static int            NumBroadcastAddresses;
  160.  
  161. XdmcpRegisterBroadcastAddress (addr)
  162.     struct sockaddr_in    *addr;
  163. {
  164.     struct sockaddr_in    *bcast;
  165.     if (NumBroadcastAddresses >= MAX_BROADCAST)
  166.     return;
  167.     bcast = &BroadcastAddresses[NumBroadcastAddresses++];
  168.     bzero (bcast, sizeof (struct sockaddr_in));
  169.     bcast->sin_family = addr->sin_family;
  170.     bcast->sin_port = htons (xdm_udp_port);
  171.     bcast->sin_addr = addr->sin_addr;
  172. }
  173.  
  174. /*
  175.  * Each authentication type is registered here; Validator
  176.  * will be called to check all access attempts using
  177.  * the specified authentication type
  178.  */
  179.  
  180. static ARRAYofARRAY8    AuthenticationNames, AuthenticationDatas;
  181. typedef struct _AuthenticationFuncs {
  182.     Bool    (*Validator)();
  183.     Bool    (*Generator)();
  184.     Bool    (*AddAuth)();
  185. } AuthenticationFuncsRec, *AuthenticationFuncsPtr;
  186.  
  187. static AuthenticationFuncsPtr    AuthenticationFuncsList;
  188.  
  189. XdmcpRegisterAuthentication (name, namelen, data, datalen, Validator, Generator, AddAuth)
  190.     char    *name;
  191.     int        namelen;
  192.     char    *data;
  193.     int        datalen;
  194.     Bool    (*Validator)();
  195.     Bool    (*Generator)();
  196.     Bool    (*AddAuth)();
  197. {
  198.     int        i;
  199.     ARRAY8  AuthenticationName, AuthenticationData;
  200.     static AuthenticationFuncsPtr    newFuncs;
  201.  
  202.     if (!XdmcpAllocARRAY8 (&AuthenticationName, namelen))
  203.     return;
  204.     if (!XdmcpAllocARRAY8 (&AuthenticationData, datalen))
  205.     {
  206.     XdmcpDisposeARRAY8 (&AuthenticationName);
  207.     return;
  208.     }
  209.     for (i = 0; i < namelen; i++)
  210.     AuthenticationName.data[i] = name[i];
  211.     for (i = 0; i < datalen; i++)
  212.     AuthenticationData.data[i] = data[i];
  213.     if (!(XdmcpReallocARRAYofARRAY8 (&AuthenticationNames,
  214.                      AuthenticationNames.length + 1) &&
  215.       XdmcpReallocARRAYofARRAY8 (&AuthenticationDatas,
  216.                      AuthenticationDatas.length + 1) &&
  217.       (newFuncs = (AuthenticationFuncsPtr) xalloc (
  218.             (AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec)))))
  219.     {
  220.     XdmcpDisposeARRAY8 (&AuthenticationName);
  221.     XdmcpDisposeARRAY8 (&AuthenticationData);
  222.     return;
  223.     }
  224.     for (i = 0; i < AuthenticationNames.length - 1; i++)
  225.     newFuncs[i] = AuthenticationFuncsList[i];
  226.     newFuncs[AuthenticationNames.length-1].Validator = Validator;
  227.     newFuncs[AuthenticationNames.length-1].Generator = Generator;
  228.     newFuncs[AuthenticationNames.length-1].AddAuth = AddAuth;
  229.     xfree (AuthenticationFuncsList);
  230.     AuthenticationFuncsList = newFuncs;
  231.     AuthenticationNames.data[AuthenticationNames.length-1] = AuthenticationName;
  232.     AuthenticationDatas.data[AuthenticationDatas.length-1] = AuthenticationData;
  233. }
  234.  
  235. /*
  236.  * Select the authentication type to be used; this is
  237.  * set by the manager of the host to be connected to.
  238.  */
  239.  
  240. ARRAY8        noAuthenticationName = {(CARD16) 0, (CARD8Ptr) 0};
  241. ARRAY8        noAuthenticationData = {(CARD16) 0, (CARD8Ptr) 0};
  242. ARRAY8Ptr    AuthenticationName = &noAuthenticationName;
  243. ARRAY8Ptr    AuthenticationData = &noAuthenticationData;
  244. AuthenticationFuncsPtr    AuthenticationFuncs;
  245.  
  246. XdmcpSetAuthentication (name)
  247.     ARRAY8Ptr    name;
  248. {
  249.     int    i;
  250.  
  251.     XdmcpDisposeARRAY8 (AuthenticationName);
  252.     for (i = 0; i < AuthenticationNames.length; i++)
  253.     if (XdmcpARRAY8Equal (&AuthenticationNames.data[i], name))
  254.     {
  255.         AuthenticationName = &AuthenticationNames.data[i];
  256.         AuthenticationData = &AuthenticationDatas.data[i];
  257.         AuthenticationFuncs = &AuthenticationFuncsList[i];
  258.         break;
  259.     }
  260. }
  261.  
  262. /*
  263.  * Register the host address for the display
  264.  */
  265.  
  266. static ARRAY16        ConnectionTypes;
  267. static ARRAYofARRAY8    ConnectionAddresses;
  268. static long        xdmcpGeneration;
  269.  
  270. XdmcpRegisterConnection (type, address, addrlen)
  271.     int        type;
  272.     char    *address;
  273.     int        addrlen;
  274. {
  275.     int        i;
  276.     CARD8   *newAddress;
  277.  
  278.     if (xdmcpGeneration != serverGeneration)
  279.     {
  280.     XdmcpDisposeARRAY16 (&ConnectionTypes);
  281.     XdmcpDisposeARRAYofARRAY8 (&ConnectionAddresses);
  282.     xdmcpGeneration = serverGeneration;
  283.     }
  284.     newAddress = (CARD8 *) xalloc (addrlen * sizeof (CARD8));
  285.     if (!newAddress)
  286.     return;
  287.     if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1))
  288.     {
  289.     xfree (newAddress);
  290.     return;
  291.     }
  292.     if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses,
  293.                     ConnectionAddresses.length +  1))
  294.     {
  295.     xfree (newAddress);
  296.     return;
  297.     }
  298.     ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type;
  299.     for (i = 0; i < addrlen; i++)
  300.     newAddress[i] = address[i];
  301.     ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress;
  302.     ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen;
  303. }
  304.  
  305. /*
  306.  * Register an Authorization Name.  XDMCP advertises this list
  307.  * to the manager.
  308.  */
  309.  
  310. static ARRAYofARRAY8    AuthorizationNames;
  311.  
  312. XdmcpRegisterAuthorizations ()
  313. {
  314.     XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames);
  315.     RegisterAuthorizations ();
  316. }
  317.  
  318. XdmcpRegisterAuthorization (name, namelen)
  319.     char    *name;
  320.     int        namelen;
  321. {
  322.     ARRAY8  authName;
  323.     int        i;
  324.  
  325.     authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8));
  326.     if (!authName.data)
  327.     return;
  328.     if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1))
  329.     {
  330.     xfree (authName.data);
  331.     return;
  332.     }
  333.     for (i = 0; i < namelen; i++)
  334.     authName.data[i] = (CARD8) name[i];
  335.     authName.length = namelen;
  336.     AuthorizationNames.data[AuthorizationNames.length-1] = authName;
  337. }
  338.  
  339. /*
  340.  * Register the DisplayClass string
  341.  */
  342.  
  343. ARRAY8    DisplayClass;
  344.  
  345. XdmcpRegisterDisplayClass (name, length)
  346.     char    *name;
  347.     int        length;
  348. {
  349.     int        i;
  350.  
  351.     XdmcpDisposeARRAY8 (&DisplayClass);
  352.     if (!XdmcpAllocARRAY8 (&DisplayClass, length))
  353.     return;
  354.     for (i = 0; i < length; i++)
  355.     DisplayClass.data[i] = (CARD8) name[i];
  356. }
  357.  
  358. /*
  359.  * Register the Manufacturer display ID
  360.  */
  361.  
  362. ARRAY8 ManufacturerDisplayID;
  363.  
  364. XdmcpRegisterManufacturerDisplayID (name, length)
  365.     char    *name;
  366.     int        length;
  367. {
  368.     int        i;
  369.  
  370.     XdmcpDisposeARRAY8 (&ManufacturerDisplayID);
  371.     if (!XdmcpAllocARRAY8 (&ManufacturerDisplayID, length))
  372.     return;
  373.     for (i = 0; i < length; i++)
  374.     ManufacturerDisplayID.data[i] = (CARD8) name[i];
  375. }
  376.  
  377. /* 
  378.  * initialize XDMCP; create the socket, compute the display
  379.  * number, set up the state machine
  380.  */
  381.  
  382. void 
  383. XdmcpInit()
  384. {
  385.     state = XDM_INIT_STATE;
  386. #ifdef HASDES
  387.     if (xdmAuthCookie)
  388.     XdmAuthenticationInit (xdmAuthCookie, strlen (xdmAuthCookie));
  389. #endif
  390.     if (state != XDM_OFF)
  391.     {
  392.     XdmcpRegisterAuthorizations();
  393.     XdmcpRegisterDisplayClass (defaultDisplayClass, strlen (defaultDisplayClass));
  394.     AccessUsingXdmcp();
  395.     RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
  396.                         (pointer) 0);
  397.         timeOutRtx = 0;
  398.         DisplayNumber = (CARD16) atoi(display);
  399.         get_xdmcp_sock();
  400.         send_packet();
  401.     }
  402. }
  403.  
  404. void
  405. XdmcpReset ()
  406. {
  407.     state = XDM_INIT_STATE;
  408.     if (state != XDM_OFF)
  409.     {
  410.     RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
  411.                         (pointer) 0);
  412.         timeOutRtx = 0;
  413.         send_packet();
  414.     }
  415. }
  416.  
  417. /*
  418.  * Called whenever a new connection is created; notices the
  419.  * first connection and saves it to terminate the session
  420.  * when it is closed
  421.  */
  422.  
  423. void
  424. XdmcpOpenDisplay(sock)
  425.     int    sock;
  426. {
  427.     extern void AugmentSelf();
  428.  
  429.     if (state != XDM_AWAIT_MANAGE_RESPONSE)
  430.     return;
  431.     state = XDM_RUN_SESSION;
  432.     sessionSocket = sock;
  433.     /* permit access control manipulations from this host */
  434.     AugmentSelf(sock);
  435. }
  436.  
  437. void 
  438. XdmcpCloseDisplay(sock)
  439.     int    sock;
  440. {
  441.     if ((state != XDM_RUN_SESSION && state != XDM_AWAIT_ALIVE_RESPONSE)
  442.     || sessionSocket != sock)
  443.         return;
  444.     state = XDM_INIT_STATE;
  445.     if (OneSession)
  446.     dispatchException |= DE_TERMINATE;
  447.     else
  448.     dispatchException |= DE_RESET;
  449.     isItTimeToYield = TRUE;
  450. }
  451.  
  452. /*
  453.  * called before going to sleep, this routine
  454.  * may modify the timeout value about to be sent
  455.  * to select; in this way XDMCP can do appropriate things
  456.  * dynamically while starting up
  457.  */
  458.  
  459. /*ARGSUSED*/
  460. static void
  461. XdmcpBlockHandler(data, wt, LastSelectMask)
  462.     pointer        data;   /* unused */
  463.     struct timeval  **wt;
  464.     long        *LastSelectMask;
  465. {
  466.     long millisToGo, wtMillis;
  467.     static struct timeval waittime;
  468.  
  469.     if (state == XDM_OFF)
  470.     return;
  471.     *LastSelectMask |= (1 << xdmcpSocket);
  472.     if (timeOutTime == 0)
  473.     return;
  474.     millisToGo = timeOutTime - GetTimeInMillis() + 1;
  475.     if (millisToGo < 0)
  476.     millisToGo = 0;
  477.     if (*wt == NULL)
  478.     {
  479.     waittime.tv_sec = (millisToGo) / 1000;
  480.     waittime.tv_usec = 1000 * (millisToGo % 1000);
  481.     *wt = &waittime;
  482.     }
  483.     else
  484.     {
  485.     wtMillis = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000;
  486.     if (millisToGo < wtMillis)
  487.      {
  488.         (*wt)->tv_sec = (millisToGo) / 1000;
  489.         (*wt)->tv_usec = 1000 * (millisToGo % 1000);
  490.     }
  491.     }
  492. }
  493.  
  494. /*
  495.  * called after select returns; this routine will
  496.  * recognise when XDMCP packets await and
  497.  * process them appropriately
  498.  */
  499.  
  500. /*ARGSUSED*/
  501. static void
  502. XdmcpWakeupHandler(data, i, LastSelectMask)
  503.     pointer data;   /* unused */
  504.     int        i;
  505.     long    *LastSelectMask;
  506. {
  507.     long    devicesReadable[mskcnt];
  508.  
  509.     if (state == XDM_OFF)
  510.     return;
  511.     if (i > 0)
  512.     {
  513.     if (GETBIT(LastSelectMask, xdmcpSocket))
  514.     {
  515.         receive_packet();
  516.         BITCLEAR(LastSelectMask, xdmcpSocket);
  517.     } 
  518.     MASKANDSETBITS(devicesReadable, LastSelectMask, EnabledDevices);
  519.     if (ANYSET(devicesReadable))
  520.     {
  521.         if (state == XDM_AWAIT_USER_INPUT)
  522.         restart();
  523.         else if (state == XDM_RUN_SESSION)
  524.         keepaliveDormancy = defaultKeepaliveDormancy;
  525.     }
  526.     if (ANYSET(AllClients) && state == XDM_RUN_SESSION)
  527.         timeOutTime = GetTimeInMillis() +  keepaliveDormancy * 1000;
  528.     }
  529.     else if (timeOutTime && GetTimeInMillis() >= timeOutTime)
  530.     {
  531.         if (state == XDM_RUN_SESSION)
  532.         {
  533.         state = XDM_KEEPALIVE;
  534.         send_packet();
  535.         }
  536.         else
  537.         timeout();
  538.     }
  539. }
  540.  
  541. /*
  542.  * This routine should be called from the routine that drives the
  543.  * user's host menu when the user selects a host
  544.  */
  545.  
  546. XdmcpSelectHost(host_sockaddr, host_len, AuthenticationName)
  547.     struct sockaddr_in    *host_sockaddr;
  548.     int            host_len;
  549.     ARRAY8Ptr        AuthenticationName;
  550. {
  551.     state = XDM_START_CONNECTION;
  552.     bcopy(host_sockaddr, &req_sockaddr, host_len);
  553.     req_socklen = host_len;
  554.     XdmcpSetAuthentication (AuthenticationName);
  555.     send_packet();
  556. }
  557.  
  558. /*
  559.  * !!! this routine should be replaced by a routine that adds
  560.  * the host to the user's host menu. the current version just
  561.  * selects the first host to respond with willing message.
  562.  */
  563.  
  564. /*ARGSUSED*/
  565. XdmcpAddHost(from, fromlen, AuthenticationName, hostname, status)
  566.     struct sockaddr_in  *from;
  567.     ARRAY8Ptr        AuthenticationName, hostname, status;
  568. {
  569.     XdmcpSelectHost(from, fromlen, AuthenticationName);
  570. }
  571.  
  572. /*
  573.  * A message is queued on the socket; read it and
  574.  * do the appropriate thing
  575.  */
  576.  
  577. ARRAY8    UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" };
  578.  
  579. static
  580. receive_packet()
  581. {
  582.     struct sockaddr_in from;
  583.     int fromlen = sizeof(struct sockaddr_in);
  584.     XdmcpHeader    header;
  585.  
  586.     /* read message off socket */
  587.     if (!XdmcpFill (xdmcpSocket, &buffer, (struct sockaddr *) &from, &fromlen))
  588.     return;
  589.  
  590.     /* reset retransmission backoff */
  591.     timeOutRtx = 0;
  592.  
  593.     if (!XdmcpReadHeader (&buffer, &header))
  594.     return;
  595.  
  596.     if (header.version != XDM_PROTOCOL_VERSION)
  597.     return;
  598.  
  599.     switch (header.opcode) {
  600.     case WILLING:
  601.     recv_willing_msg(&from, fromlen, header.length);
  602.     break;
  603.     case UNWILLING:
  604.     XdmcpFatal("Manager unwilling", &UnwillingMessage);
  605.     break;
  606.     case ACCEPT:
  607.     recv_accept_msg(header.length);
  608.     break;
  609.     case DECLINE:
  610.     recv_decline_msg(header.length);
  611.     break;
  612.     case REFUSE:
  613.     recv_refuse_msg(header.length);
  614.     break;
  615.     case FAILED:
  616.     recv_failed_msg(header.length);
  617.     break;
  618.     case ALIVE:
  619.     recv_alive_msg(header.length);
  620.     break;
  621.     }
  622. }
  623.  
  624. /*
  625.  * send the appropriate message given the current state
  626.  */
  627.  
  628. static
  629. send_packet()
  630. {
  631.     switch (state) {
  632.     case XDM_QUERY:
  633.     case XDM_BROADCAST:
  634.     case XDM_INDIRECT:
  635.     send_query_msg();
  636.     break;
  637.     case XDM_START_CONNECTION:
  638.     send_request_msg();
  639.     break;
  640.     case XDM_MANAGE:
  641.     send_manage_msg();
  642.     break;
  643.     case XDM_KEEPALIVE:
  644.     send_keepalive_msg();
  645.     break;
  646.     }
  647.     timeOutTime = GetTimeInMillis() 
  648.     + MIN (XDM_MIN_RTX * (1 << timeOutRtx), XDM_MAX_RTX) * 1000;
  649. }
  650.  
  651. /*
  652.  * The session is declared dead for some reason; too many
  653.  * timeouts, or Keepalive failure.
  654.  */
  655.  
  656. XdmcpDeadSession (reason)
  657.     char *reason;
  658. {
  659.     printf ("XDM: %s, declaring session dead\n", reason);
  660.     state = XDM_INIT_STATE;
  661.     isItTimeToYield = TRUE;
  662.     dispatchException |= DE_RESET;
  663.     timeOutTime = 0;
  664.     timeOutRtx = 0;
  665.     send_packet();
  666. }
  667.  
  668. /*
  669.  * Timeout waiting for an XDMCP response.
  670.  */
  671.  
  672. static 
  673. timeout()
  674. {
  675.     timeOutRtx++;
  676.     if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT )
  677.     {
  678.     XdmcpDeadSession ("too many keepalive retransmissions");
  679.     return;
  680.     }
  681.     else if (timeOutRtx >= XDM_RTX_LIMIT)
  682.     {
  683.     printf("XDM: too many retransmissions\n");
  684.     state = XDM_AWAIT_USER_INPUT;
  685.     timeOutTime = 0;
  686.     timeOutRtx = 0;
  687.     return;
  688.     }
  689.  
  690.     switch (state) {
  691.     case XDM_COLLECT_QUERY:
  692.     state = XDM_QUERY;
  693.     break;
  694.     case XDM_COLLECT_BROADCAST_QUERY:
  695.     state = XDM_BROADCAST;
  696.     break;
  697.     case XDM_COLLECT_INDIRECT_QUERY:
  698.     state = XDM_INDIRECT;
  699.     break;
  700.     case XDM_AWAIT_REQUEST_RESPONSE:
  701.     state = XDM_START_CONNECTION;
  702.     break;
  703.     case XDM_AWAIT_MANAGE_RESPONSE:
  704.     state = XDM_MANAGE;
  705.     break;
  706.     case XDM_AWAIT_ALIVE_RESPONSE:
  707.     state = XDM_KEEPALIVE;
  708.     break;
  709.     }
  710.     send_packet();
  711. }
  712.  
  713. static
  714. restart()
  715. {
  716.     state = XDM_INIT_STATE;
  717.     timeOutRtx = 0;
  718.     send_packet();
  719. }
  720.  
  721. XdmcpCheckAuthentication (Name, Data, packet_type)
  722.     ARRAY8Ptr    Name, Data;
  723.     int    packet_type;
  724. {
  725.     return (XdmcpARRAY8Equal (Name, AuthenticationName) &&
  726.         (AuthenticationName->length == 0 ||
  727.          (*AuthenticationFuncs->Validator) (AuthenticationData, Data, packet_type)));
  728. }
  729.  
  730. XdmcpAddAuthorization (name, data)
  731.     ARRAY8Ptr    name, data;
  732. {
  733.     Bool    (*AddAuth)(), AddAuthorization();
  734.  
  735.     if (AuthenticationFuncs && AuthenticationFuncs->AddAuth)
  736.     AddAuth = AuthenticationFuncs->AddAuth;
  737.     else
  738.     AddAuth = AddAuthorization;
  739.     return (*AddAuth) ((unsigned short)name->length,
  740.                (char *)name->data,
  741.                (unsigned short)data->length,
  742.                (char *)data->data);
  743. }
  744.  
  745. /*
  746.  * from here to the end of this file are routines private
  747.  * to the state machine.
  748.  */
  749.  
  750. static
  751. get_xdmcp_sock()
  752. {
  753.     int soopts = 1;
  754.  
  755.     if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  756.     XdmcpWarning("UDP socket creation failed");
  757. #ifdef SO_BROADCAST
  758.     else if (setsockopt(xdmcpSocket, SOL_SOCKET, SO_BROADCAST, &soopts,
  759.     sizeof(soopts)) < 0)
  760.         XdmcpWarning("UDP set broadcast socket-option failed");
  761. #endif SO_BROADCAST
  762. }
  763.  
  764. static
  765. send_query_msg()
  766. {
  767.     XdmcpHeader    header;
  768.     Bool    broadcast = FALSE;
  769.     int        i;
  770.  
  771.     header.version = XDM_PROTOCOL_VERSION;
  772.     switch(state){
  773.     case XDM_QUERY:
  774.     header.opcode = (CARD16) QUERY; 
  775.     state = XDM_COLLECT_QUERY;
  776.     break;
  777.     case XDM_BROADCAST:
  778.     header.opcode = (CARD16) BROADCAST_QUERY;
  779.     state = XDM_COLLECT_BROADCAST_QUERY;
  780.     broadcast = TRUE;
  781.     break;
  782.     case XDM_INDIRECT:
  783.     header.opcode = (CARD16) INDIRECT_QUERY;
  784.     state = XDM_COLLECT_INDIRECT_QUERY;
  785.     break;
  786.     }
  787.     header.length = 1;
  788.     for (i = 0; i < AuthenticationNames.length; i++)
  789.     header.length += 2 + AuthenticationNames.data[i].length;
  790.  
  791.     XdmcpWriteHeader (&buffer, &header);
  792.     XdmcpWriteARRAYofARRAY8 (&buffer, &AuthenticationNames);
  793.     if (broadcast)
  794.     {
  795.     int i;
  796.  
  797.     for (i = 0; i < NumBroadcastAddresses; i++)
  798.         XdmcpFlush (xdmcpSocket, &buffer, &BroadcastAddresses[i],
  799.             sizeof (struct sockaddr_in));
  800.     }
  801.     else
  802.     {
  803.     XdmcpFlush (xdmcpSocket, &buffer, &ManagerAddress,
  804.             sizeof (ManagerAddress));
  805.     }
  806. }
  807.  
  808. static
  809. recv_willing_msg(from, fromlen, length)
  810.     struct sockaddr_in    *from;
  811.     int            fromlen;
  812.     unsigned        length;
  813. {
  814.     ARRAY8    authenticationName;
  815.     ARRAY8    hostname;
  816.     ARRAY8    status;
  817.  
  818.     authenticationName.data = 0;
  819.     hostname.data = 0;
  820.     status.data = 0;
  821.     if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
  822.     XdmcpReadARRAY8 (&buffer, &hostname) &&
  823.     XdmcpReadARRAY8 (&buffer, &status))
  824.     {
  825.         if (length == 6 + authenticationName.length +
  826.               hostname.length + status.length)
  827.         {
  828.         switch (state)
  829.         {
  830.         case XDM_COLLECT_QUERY:
  831.             XdmcpSelectHost(from, fromlen, &authenticationName);
  832.             break;
  833.         case XDM_COLLECT_BROADCAST_QUERY:
  834.         case XDM_COLLECT_INDIRECT_QUERY:
  835.             XdmcpAddHost(from, fromlen, &authenticationName, &hostname, &status);
  836.             break;
  837.             }
  838.         }
  839.     }
  840.     XdmcpDisposeARRAY8 (&authenticationName);
  841.     XdmcpDisposeARRAY8 (&hostname);
  842.     XdmcpDisposeARRAY8 (&status);
  843. }
  844.  
  845. static
  846. send_request_msg()
  847. {
  848.     XdmcpHeader        header;
  849.     int            length;
  850.     int            i;
  851.     ARRAY8        authenticationData;
  852.  
  853.     header.version = XDM_PROTOCOL_VERSION;
  854.     header.opcode = (CARD16) REQUEST;
  855.  
  856.     length = 2;                        /* display number */
  857.     length += 1 + 2 * ConnectionTypes.length;        /* connection types */
  858.     length += 1;                    /* connection addresses */
  859.     for (i = 0; i < ConnectionAddresses.length; i++)
  860.     length += 2 + ConnectionAddresses.data[i].length;
  861.     authenticationData.length = 0;
  862.     authenticationData.data = 0;
  863.     if (AuthenticationFuncs)
  864.     {
  865.     (*AuthenticationFuncs->Generator) (AuthenticationData,
  866.                        &authenticationData,
  867.                         REQUEST);
  868.     }
  869.     length += 2 + AuthenticationName->length;        /* authentication name */
  870.     length += 2 + authenticationData.length;        /* authentication data */
  871.     length += 1;                    /* authorization names */
  872.     for (i = 0; i < AuthorizationNames.length; i++)
  873.     length += 2 + AuthorizationNames.data[i].length;
  874.     length += 2 + ManufacturerDisplayID.length;        /* display ID */
  875.     header.length = length;
  876.  
  877.     if (!XdmcpWriteHeader (&buffer, &header))
  878.     {
  879.     XdmcpDisposeARRAY8 (&authenticationData);
  880.     return;
  881.     }
  882.     XdmcpWriteCARD16 (&buffer, DisplayNumber);
  883.     XdmcpWriteARRAY16 (&buffer, &ConnectionTypes);
  884.     XdmcpWriteARRAYofARRAY8 (&buffer, &ConnectionAddresses);
  885.  
  886.     XdmcpWriteARRAY8 (&buffer, AuthenticationName);
  887.     XdmcpWriteARRAY8 (&buffer, &authenticationData);
  888.     XdmcpDisposeARRAY8 (&authenticationData);
  889.     XdmcpWriteARRAYofARRAY8 (&buffer, &AuthorizationNames);
  890.     XdmcpWriteARRAY8 (&buffer, &ManufacturerDisplayID);
  891.     if (XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen))
  892.     state = XDM_AWAIT_REQUEST_RESPONSE;
  893. }
  894.  
  895. static
  896. recv_accept_msg(length)
  897.     unsigned        length;
  898. {
  899.     CARD32  AcceptSessionID;
  900.     ARRAY8  AcceptAuthenticationName, AcceptAuthenticationData;
  901.     ARRAY8  AcceptAuthorizationName, AcceptAuthorizationData;
  902.  
  903.     if (state != XDM_AWAIT_REQUEST_RESPONSE)
  904.     return;
  905.     AcceptAuthenticationName.data = 0;
  906.     AcceptAuthenticationData.data = 0;
  907.     AcceptAuthorizationName.data = 0;
  908.     AcceptAuthorizationData.data = 0;
  909.     if (XdmcpReadCARD32 (&buffer, &AcceptSessionID) &&
  910.     XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationName) &&
  911.     XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationData) &&
  912.     XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationName) &&
  913.     XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationData))
  914.     {
  915.         if (length == 12 + AcceptAuthenticationName.length +
  916.                      AcceptAuthenticationData.length +
  917.                      AcceptAuthorizationName.length +
  918.                       AcceptAuthorizationData.length)
  919.         {
  920.         if (!XdmcpCheckAuthentication (&AcceptAuthenticationName,
  921.                       &AcceptAuthenticationData))
  922.         {
  923.         XdmcpFatal ("Authentication Failure", &AcceptAuthenticationName);
  924.         }
  925.         /* if the authorization specified in the packet fails
  926.          * to be acceptable, enable the local addresses
  927.          */
  928.         if (!XdmcpAddAuthorization (&AcceptAuthorizationName,
  929.                     &AcceptAuthorizationData))
  930.         {
  931.         AddLocalHosts ();
  932.         }
  933.         SessionID = AcceptSessionID;
  934.             state = XDM_MANAGE;
  935.             send_packet();
  936.         }
  937.     }
  938.     XdmcpDisposeARRAY8 (&AcceptAuthenticationName);
  939.     XdmcpDisposeARRAY8 (&AcceptAuthenticationData);
  940.     XdmcpDisposeARRAY8 (&AcceptAuthorizationName);
  941.     XdmcpDisposeARRAY8 (&AcceptAuthorizationData);
  942. }
  943.  
  944. static
  945. recv_decline_msg(length)
  946.     unsigned        length;
  947. {
  948.     ARRAY8  Status, DeclineAuthenticationName, DeclineAuthenticationData;
  949.  
  950.     Status.data = 0;
  951.     DeclineAuthenticationName.data = 0;
  952.     DeclineAuthenticationData.data = 0;
  953.     if (XdmcpReadARRAY8 (&buffer, &Status) &&
  954.     XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationName) &&
  955.     XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationData))
  956.     {
  957.         if (length == 6 + Status.length +
  958.                     DeclineAuthenticationName.length +
  959.                      DeclineAuthenticationData.length &&
  960.         XdmcpCheckAuthentication (&DeclineAuthenticationName,
  961.                       &DeclineAuthenticationData))
  962.         {
  963.         XdmcpFatal ("Session declined", &Status);
  964.         }
  965.     }
  966.     XdmcpDisposeARRAY8 (&Status);
  967.     XdmcpDisposeARRAY8 (&DeclineAuthenticationName);
  968.     XdmcpDisposeARRAY8 (&DeclineAuthenticationData);
  969. }
  970.  
  971. static
  972. send_manage_msg()
  973. {
  974.     XdmcpHeader    header;
  975.  
  976.     header.version = XDM_PROTOCOL_VERSION;
  977.     header.opcode = (CARD16) MANAGE;
  978.     header.length = 8 + DisplayClass.length;
  979.  
  980.     if (!XdmcpWriteHeader (&buffer, &header))
  981.     return;
  982.     XdmcpWriteCARD32 (&buffer, SessionID);
  983.     XdmcpWriteCARD16 (&buffer, DisplayNumber);
  984.     XdmcpWriteARRAY8 (&buffer, &DisplayClass);
  985.     state = XDM_AWAIT_MANAGE_RESPONSE;
  986.     XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen);
  987. }
  988.  
  989. static
  990. recv_refuse_msg(length)
  991.     unsigned        length;
  992. {
  993.     CARD32  RefusedSessionID;
  994.  
  995.     if (state != XDM_AWAIT_MANAGE_RESPONSE)
  996.     return;
  997.     if (length != 4)
  998.     return;
  999.     if (XdmcpReadCARD32 (&buffer, &RefusedSessionID))
  1000.     {
  1001.     if (RefusedSessionID == SessionID)
  1002.     {
  1003.             state = XDM_START_CONNECTION;
  1004.             send_packet();
  1005.     }
  1006.     }
  1007. }
  1008.  
  1009. static
  1010. recv_failed_msg(length)
  1011.     unsigned        length;
  1012. {
  1013.     CARD32  FailedSessionID;
  1014.     ARRAY8  Status;
  1015.  
  1016.     if (state != XDM_AWAIT_MANAGE_RESPONSE)
  1017.     return;
  1018.     Status.data = 0;
  1019.     if (XdmcpReadCARD32 (&buffer, &FailedSessionID) &&
  1020.     XdmcpReadARRAY8 (&buffer, &Status))
  1021.     {
  1022.         if (length == 5 + Status.length &&
  1023.         SessionID == FailedSessionID)
  1024.     {
  1025.         XdmcpFatal ("Session failed", &Status);
  1026.     }
  1027.     }
  1028.     XdmcpDisposeARRAY8 (&Status);
  1029. }
  1030.  
  1031. static
  1032. send_keepalive_msg()
  1033. {
  1034.     XdmcpHeader    header;
  1035.  
  1036.     header.version = XDM_PROTOCOL_VERSION;
  1037.     header.opcode = (CARD16) KEEPALIVE;
  1038.     header.length = 6;
  1039.  
  1040.     XdmcpWriteHeader (&buffer, &header);
  1041.     XdmcpWriteCARD16 (&buffer, DisplayNumber);
  1042.     XdmcpWriteCARD32 (&buffer, SessionID);
  1043.  
  1044.     state = XDM_AWAIT_ALIVE_RESPONSE;
  1045.     XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen);
  1046. }
  1047.  
  1048. static
  1049. recv_alive_msg (length)
  1050.     unsigned        length;
  1051. {
  1052.     CARD8   SessionRunning;
  1053.     CARD32  AliveSessionID;
  1054.  
  1055.     if (state != XDM_AWAIT_ALIVE_RESPONSE)
  1056.     return;
  1057.     if (length != 5)
  1058.     return;
  1059.     if (XdmcpReadCARD8 (&buffer, &SessionRunning) &&
  1060.     XdmcpReadCARD32 (&buffer, &AliveSessionID))
  1061.     {
  1062.         if (SessionRunning && AliveSessionID == SessionID)
  1063.         {
  1064.         /* backoff dormancy period */
  1065.         state = XDM_RUN_SESSION;
  1066.         if (TimeSinceLastInputEvent() > keepaliveDormancy * 1000)
  1067.             keepaliveDormancy = MIN(keepaliveDormancy << 1, XDM_MAX_DORMANCY);
  1068.         timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
  1069.         }
  1070.     else
  1071.         {
  1072.         XdmcpDeadSession ("Alive respose indicates session dead");
  1073.         }
  1074.     }
  1075. }
  1076.  
  1077. static 
  1078. XdmcpFatal (type, status)
  1079.     char    *type;
  1080.     ARRAY8Ptr    status;
  1081. {
  1082.     extern void AbortDDX();
  1083.  
  1084.     printf("XDMCP fatal error: %s %*.*s\n", type,
  1085.        status->length, status->length, status->data);
  1086.     AbortDDX ();
  1087.     exit (1);
  1088. }
  1089.  
  1090. static 
  1091. XdmcpWarning(str)
  1092.     char *str;
  1093. {
  1094.     printf("XDMCP warning: %s\n", str);
  1095. }
  1096.  
  1097. static
  1098. get_manager_by_name(argc, argv, i)
  1099.     int        argc, i;
  1100.     char    **argv;
  1101. {
  1102.     struct hostent *hep;
  1103.  
  1104.     if (i == argc)
  1105.     {
  1106.     printf("Xserver: missing host name in command line\n");
  1107.     exit(1);
  1108.     }
  1109.     if (!(hep = gethostbyname(argv[i])))
  1110.     {
  1111.     printf("Xserver: unknown host: %s\n", argv[i]);
  1112.     exit(1);
  1113.     }
  1114.     if (hep->h_length == sizeof (struct in_addr))
  1115.     {
  1116.     bcopy(hep->h_addr, &ManagerAddress.sin_addr, hep->h_length);
  1117.     ManagerAddress.sin_family = AF_INET;
  1118.     ManagerAddress.sin_port = htons (xdm_udp_port);
  1119.     }
  1120.     else
  1121.     {
  1122.     printf ("Xserver: host on strange network %s\n", argv[i]);
  1123.     exit (1);
  1124.     }
  1125. }
  1126. #endif /* XDMCP */
  1127.